`timescale 1ns/1ps
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Project Name : 
// Author 		: HiDark
// File   		: id2ex.sv
// Create 		: 2023-04-20 12:12:34
// Revise 		: 2023-04-20 12:12:34
// Abstract 	: 
// -----------------------------------------------------------------------------
`include "defines.svh"

module id2ex(
	input	logic			clk,    // Clock
	input	logic			rst_n,  // Synchronous reset active low
	input 	logic	[31:0]	PC,	
	// regbank address and data
	input 	logic	[ 4:0]	rs1  	,
	input 	logic	[ 4:0]	rs2  	,
	input 	logic	[ 4:0]	rd      ,
	input 	logic	[31:0]	rs1_data  ,
	input 	logic	[31:0]	rs2_data ,
	input 	logic	[31:0]	imm ,
	// forward
	input	logic	[31:0]	alu_out,
	input	logic	[ 4:0]	wb_addr_ex2mem,
	input	logic			wb_en_ex2mem,
	input	logic	[31:0]	alu_out_ex2mem,
	// control signals	
	input 	logic			alu_srcA,	//alu operand A
	input 	logic	[ 1:0]	alu_srcB,	//alu operand B
	input 	logic	[ 3:0]	alu_ctrl,	//alu control
	input 	logic	[ 3:0]	branch,  	// pc 
	input 	logic			wb_en,	 	//Register bank write enable
	input 	logic			wb_src, 	// 0 alu or 1 mem
	input 	logic			mem_wr,  	// data mem write enable
	input 	logic			mem_rd,  	// data mem read  enable  
	input 	logic	[ 2:0]	mem_ctrl, 	// data mem control signal	
	// control hazard
	input 	logic			PCjump_flag, 
	input  	logic          	refetch_flag,   // nop the pipeline	

    output 	logic	[31:0]	PC_id2ex,  
	// regbank address and data
	output 	logic	[31:0]	rs1_data_id2ex ,
	output 	logic	[31:0]	rs2_data_id2ex ,
	output 	logic	[ 4:0]	rs1_id2ex 		,
	output 	logic	[ 4:0]	rs2_id2ex 		,	
	output 	logic	[ 4:0]	rd_id2ex      ,
	output 	logic	[31:0]	imm_id2ex ,
	// control signals
	output 	logic			wb_en_id2ex ,	//Register bank write enable
	output 	logic			alu_srcA_id2ex,	//alu operand A
	output 	logic	[ 1:0]	alu_srcB_id2ex,	//alu operand B
	output 	logic	[ 3:0]	alu_ctrl_id2ex,	//alu control
	output 	logic	[ 3:0]	branch_id2ex	,	// pc 
	output 	logic			wb_src_id2ex,	// 0 alu or 1 mem
	output 	logic			mem_wr_id2ex	,	// data mem write enable 
	output 	logic			mem_rd_id2ex,  	// data mem read  enable 
	output 	logic	[ 2:0]	mem_ctrl_id2ex 	// data mem control signal	
	);


//=================================================================================
// Body
//=================================================================================

	//	reg1 read need forward
	always_ff @(posedge clk) begin 
		if(~rst_n) 
			rs1_data_id2ex	<=	'b0;
		else if (rd_id2ex == rs1&&wb_en_id2ex&&rd_id2ex!=5'd0)
			rs1_data_id2ex	<=	alu_out;
		else if (wb_addr_ex2mem == rs1
				&&wb_en_ex2mem&&wb_addr_ex2mem!=5'd0
				&&(rd_id2ex != rs1||!wb_en_id2ex))
			rs1_data_id2ex	<=	alu_out_ex2mem;
		else
			rs1_data_id2ex	<=	rs1_data;			
	end
	//	reg2 read need forward
	always_ff @(posedge clk) begin 
		if(~rst_n) 
			rs2_data_id2ex	<=	'b0;
		else if (rd_id2ex == rs2&&wb_en_id2ex&&rd_id2ex!=5'd0)
			rs2_data_id2ex	<=	alu_out;
		else if (wb_addr_ex2mem == rs2
				&&wb_en_ex2mem&&wb_addr_ex2mem!=5'd0
				&&(rd_id2ex != rs2||!wb_en_id2ex))
			rs2_data_id2ex	<=	alu_out_ex2mem;
		else
			rs2_data_id2ex	<=	rs2_data;			
	end




	always_ff @(posedge clk) begin 
		if(~rst_n) begin
			wb_en_id2ex 	<=	'b0;	
			alu_srcA_id2ex	<=	'b0;
			alu_srcB_id2ex	<=	'b0;
			alu_ctrl_id2ex	<=	'b0;
			branch_id2ex	<=	'b0;
			wb_src_id2ex	<=	'b0;
			mem_wr_id2ex	<=	'b0;
			mem_rd_id2ex	<=	'b0;
			mem_ctrl_id2ex	<=	'b0;

		end else begin
			wb_en_id2ex 	<=	(refetch_flag|PCjump_flag)?`Disable:wb_en;	
			alu_srcA_id2ex	<=	alu_srcA;
			alu_srcB_id2ex	<=	alu_srcB;
			alu_ctrl_id2ex	<=	alu_ctrl;
			//branch_id2ex	<=	PCjump_flag?`BRAN_NOJ:branch;
			branch_id2ex	<=	branch;
			wb_src_id2ex	<=	wb_src;
			mem_wr_id2ex	<=	(refetch_flag|PCjump_flag)?`Disable:mem_wr;
			mem_rd_id2ex	<=	mem_rd;
			mem_ctrl_id2ex	<=	mem_ctrl;

		end
	end
	
	always_ff @(posedge clk) begin 
		if(~rst_n) begin
			PC_id2ex		<=	'b0;		
			imm_id2ex		<=	'b0; 
			rs1_id2ex 		<=	'b0;
			rs2_id2ex 		<=	'b0;
			rd_id2ex        <=	'b0;			
		end
		else begin
			PC_id2ex		<=	PC;
			imm_id2ex		<=	imm;
			rs1_id2ex 		<=	rs1;
			rs2_id2ex 		<=	rs2;
			rd_id2ex        <=	rd;
		end
	end

endmodule